/**
 * 验证密码强度
 * @param {string} password 密码
 */
function valiPasswordStrong(password) {
    var strong = 0, character = 0, fromCharacterSets = [];
    var match = function (match, length) {
        return { match, length };
    };
    var matches = {
        'ASCII Lowercase': match(/[a-z]/, 26),
        'ASCII Uppercase': match(/[A-Z]/, 26),
        'ASCII Numbers': match(/\d/, 10),
        'ASCII Top Row Symbols': match(/[!@£#\$%\^&\*\(\)\-_=\+]/, 15),
        'ASCII Other Symbols': match(/[\?\/\.>\,<`~\\|"';:\]\}\[\{\s]/, 19),
        'Unicode Latin 1 Supplement': match(/[\u00A1-\u00FF]/, 94),
        'Unicode Latin Extended A': match(/[\u0100-\u017F]/, 128),
        'Unicode Latin Extended B': match(/[\u0180-\u024F]/, 208),
        'Unicode Latin Extended C': match(/[\u2C60-\u2C7F]/, 32),
        'Unicode Latin Extended D': match(/[\uA720-\uA7FF]/, 29),
        'Unicode Cyrillic Uppercase': match(/[\u0410-\u042F]/, 32),
        'Unicode Cyrillic Lowercase': match(/[\u0430-\u044F]/, 32)
    };
    for (var i in matches) {
        if (password.match(matches[i].match)) {
            character += matches[i].length;
            fromCharacterSets.push(i);
        }
    }
    strong = Math.log10(Math.pow(character, password.length))
    return { fromCharacterSets, strong }
}

/**
 * 笛卡尔数据积
 * @param {Array} listLv2  二维数组
 * @return {Array} 笛卡尔积
 */
function specCartesian(listLv2) {
    const merger = (a, b) => {
        const result = []
        for (const aItem of a) {
            for (const bItem of b) {
                if (Array.isArray(aItem)) {
                    result.push([...aItem, bItem])
                } else {
                    result.push([aItem, bItem])
                }
            }
        }
        return result
    }
    return listLv2.reduce((p, c) => p ? merger(p, c) : c)
}

/**
 * 对象深拷贝【中级版】不含边界情况，高级版参见lodash's _.cloneDeep()
 * @param {Object} source
 * @returns {Object}
 */
function deepCloneObj(source) {
    if (!source && typeof source !== 'object') {
        return null
    }
    const targetObj = source.constructor === Array ? [] : {}
    Object.keys(source).forEach(keys => {
        if (source[keys] && typeof source[keys] === 'object') {
            targetObj[keys] = deepCloneObj(source[keys])
        } else {
            targetObj[keys] = source[keys]
        }
    })
    return targetObj
}

/**
 * 阿拉伯数字转中文数字
 * @param {(number|string)} num 阿拉伯数字
 * @returns {string}
 */
function toChinesNum(num) {
    num = parseFloat(num)
    const chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
    const chnUnitSection = ['', '万', '亿', '万亿', '亿亿'];
    const chnUnitChar = ['', '十', '百', '千'];
    const SectionToChinese = function (section) {
        var strIns = '', chnStr = '';
        var unitPos = 0;
        var zero = true;
        while (section > 0) {
            var v = section % 10;
            if (v === 0) {
                if (!zero) {
                    zero = true;
                    chnStr = chnNumChar[v] + chnStr;
                }
            } else {
                zero = false;
                strIns = chnNumChar[v];
                strIns += chnUnitChar[unitPos];
                chnStr = strIns + chnStr;
            }
            unitPos++;
            section = Math.floor(section / 10);
        }
        return chnStr;
    }
    var unitPos = 0;
    var strIns = '', chnStr = '';
    var needZero = false;
    if (num === 0) { return chnNumChar[0]; }
    while (num > 0) {
        var section = num % 10000;
        if (needZero) {
            chnStr = chnNumChar[0] + chnStr;
        }
        strIns = SectionToChinese(section);
        strIns += (section !== 0) ? chnUnitSection[unitPos] : chnUnitSection[0];
        chnStr = strIns + chnStr;
        needZero = (section < 1000) && (section > 0);
        num = Math.floor(num / 10000);
        unitPos++;
    }
    chnStr = chnStr.replace(/一十/g, '十')
    return chnStr;
}

module.exports = {
	valiPasswordStrong,
    specCartesian,
    deepCloneObj,
    toChinesNum
}